package com.itcast.activiti.utils;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import redis.clients.jedis.Protocol;
import redis.clients.util.SafeEncoder;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Component
public class RedisUtils {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private RedisTemplate redisTemplate;


    // 请对照此例子封装自己的方法，方法名请参照http://redisdoc.com/index.html中的原生命令,请完善log

    /**
     * 写入缓存
     *
     * @param key
     * @param value
     * @return
     */
    public void set(final String key, Object value) {
        Assert.hasText(key, "key not be null or empty");
        Assert.notNull(value, "value not be null");
        boolean result = false;
        try {
            redisTemplate.opsForValue().set(key, value);
            logger.info("set redis cache \n key {} \n value {}", key, JSON.toJSONString(value));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setInteger(final String key, Object value) {
        Assert.hasText(key, "key not be null or empty");
        Assert.notNull(value, "value not be null");
        boolean result = false;
        try {
            GenericToStringSerializer genericToStringSerializer = new GenericToStringSerializer(Object.class);
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(genericToStringSerializer);
            redisTemplate.opsForValue().set(key, value);
            logger.info("set redis cache \n key {} \n value {}", key, JSON.toJSONString(value));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getInteger(final String key) {
        Assert.hasText(key, "key not be null or empty");
        try {
            GenericToStringSerializer genericToStringSerializer = new GenericToStringSerializer(Object.class);
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(genericToStringSerializer);
            return redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public Long incrby(final String key, Long value) {
        Assert.hasText(key, "key not be null or empty");
        Assert.notNull(value, "value not be null");
        try {
            return redisTemplate.opsForValue().increment(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public Long decr(final String key) {
        Assert.hasText(key, "key not be null or empty");
        try {
            return redisTemplate.opsForValue().decrement(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取key所对应的散列表的key
     *
     * @param redisKey
     * @return
     */
    public Set<Object> keys(final String redisKey) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Set<Object> result = new HashSet<>();
        try {
            result = redisTemplate.keys(redisKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 指定过期时间写入缓存
     *
     * @param key
     * @param value
     * @param expireTime
     * @return
     */
    public void setex(final String key, Object value, Long expireTime) {
        Assert.hasText(key, "key not be null or empty");
        Assert.notNull(value, "value not be null");
        Assert.notNull(expireTime, "expire time not be null");
        try {
            redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param expireTime
     */
    public void setExpire(final String key, Long expireTime) {
        Assert.hasText(key, "key not be null or empty");
        Assert.notNull(expireTime, "expire time not be null");
        if (exists(key)) {
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
        }
    }

    /**
     * 写入缓存
     *
     * @param key
     * @param value
     * @return
     */
    public boolean setnx(final String key, Object value) {
        Assert.hasText(key, "key not be null or empty");
        Assert.notNull(value, "value not be null");
        boolean result = false;
        try {
            result = redisTemplate.opsForValue().setIfAbsent(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * set key expire time
     *
     * @param key
     * @param expireTime TimeUnit is Second
     */
    public void expire(final String key, Long expireTime) {
        Assert.hasText(key, "key not be null or empty");
        Assert.notNull(expireTime, "expire time not be null");
        if (exists(key)) {
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
        }
    }


    /**
     * redis锁
     * 因为redisTemplate的setnx和expire是两步操作,所以存在死锁的问题
     *
     * @param key
     * @param value
     * @param exptime
     * @return
     */
    public boolean tryLock(final String key, final Serializable value, final long exptime) {
        Boolean b = (Boolean) redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer valueSerializer = redisTemplate.getValueSerializer();
                RedisSerializer keySerializer = redisTemplate.getKeySerializer();
                Object obj = connection.execute("set", keySerializer.serialize(key),
                        valueSerializer.serialize(value),
                        SafeEncoder.encode("NX"),
                        SafeEncoder.encode("EX"),
                        Protocol.toByteArray(exptime));
                return obj != null;
            }
        });
        return b;
    }

    /**
     * 指定key判断缓存中是否有对应的value
     *
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        Assert.hasText(key, "key not be null or empty");
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.getMessage();
        }
        return false;
    }

    /**
     * 指定key读取缓存
     *
     * @param key
     * @return
     */
    public Object get(final String key) {
        Assert.hasText(key, "key not be null or empty");
        try {
            return redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 删除对应的value
     *
     * @param key
     */
    public void del(final String key) {
        Assert.hasText(key, "key not be null or empty");
        try {
            if (exists(key)) {
                redisTemplate.delete(key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 批量删除对应的value
     *
     * @param keys
     */
    public void remove(final String... keys) {
        Assert.noNullElements(keys, "key not be null or empty");
        try {
            for (String key : keys) {
                remove(key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * ===================================================== Set类型缓存 =====================================================
     */


    /**
     * 向Set类型缓存中添加一个或多个String类型值
     *
     * @param key
     * @param value
     */
    public void sadd(final String key, Object... value) {
        Assert.hasText(key, "key not be null or empty");
        Assert.noNullElements(value, "value not be null or empty");
        try {
            Long result = redisTemplate.opsForSet().add(key, value);
            logger.info("add redis {} set values {}", key, JSON.toJSONString(value));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public boolean sismember(String key, Object value) {
        if (exists(key)) {
            return redisTemplate.opsForSet().isMember(key, value);
        }
        return false;
    }

    /**
     * 根据key查询set
     *
     * @param key
     * @return
     */
    public Set smembers(final String key) {
        Assert.hasText(key, "key not be null or empty");
        Set set = new HashSet<>();
        try {
            set = redisTemplate.opsForSet().members(key);
            logger.info("get redis set {} values {}", key, JSON.toJSONString(set));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return set;
    }

//    /**
//     * 根据key查询set
//     *
//     * @param key
//     * @return
//     */
//    public Set smembers(final String key) {
//        Assert.hasText(key, "key not be null or empty");
//        Set set = Sets.newHashSet();
//        try {
//            set = redisTemplate.opsForSet().members(key);
//            logger.info("get redis set {} values {}", key, JSON.toJSONString(set));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return set;
//    }

    /**
     * 删除对应key中的数据
     *
     * @param key
     * @param value
     */
    public Long srem(final String key, Object... value) {
        Assert.hasText(key, "key not be null or empty");
        Assert.noNullElements(value, "value not be null or empty");
        Long result = 0L;
        try {
            result = redisTemplate.opsForSet().remove(key, value);

            logger.info("remove redis set {} value {} \n result {}", key, JSON.toJSONString(value), result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public Long scard(final String key) {
        Assert.hasText(key, "key not be null or empty");
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0L;
    }


//================================================================ Map =====================================================

    /**
     * 取出指定key中的整个Map数据{name=jack, age=27}
     *
     * @param redisKey redis key
     * @return
     */
    public Map<String, Object> hgetall(final String redisKey) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        try {
            return redisTemplate.opsForHash().entries(redisKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获得指定key的Map长度
     *
     * @param redisKey redis key
     * @return
     */
    public Long hlen(final String redisKey) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Long result = 0L;
        try {
            result = redisTemplate.opsForHash().size(redisKey);
            logger.info("redisKey:{} map size is {}", redisKey, result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 判断redisKey中的map是否存在hashKey
     *
     * @param redisKey
     * @param hashKey
     * @return
     */
    public Boolean hexists(final String redisKey, final String hashKey) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Assert.hasText(hashKey, "hash key not be null or empty");
        return redisTemplate.opsForHash().hasKey(redisKey, hashKey);
    }

    /**
     * 使指定redis key，map key 的 map value 增加在 指定值
     *
     * @param redisKey redis key
     * @param hashKey  map key
     * @param value    map value 要增加的数值
     * @return
     */
    public Long hincrby(final String redisKey, final String hashKey, Long value) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Assert.hasText(hashKey, "map key not be null or empty");
        Assert.notNull(value, "value not be null");
        Long result = 0L;
        try {
            result = redisTemplate.opsForHash().increment(redisKey, hashKey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 删除给定的hashKeys
     *
     * @param redisKey redis key
     * @param hashKeys map keys
     */
    public void hdel(final String redisKey, final String... hashKeys) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Assert.noNullElements(hashKeys, "map keys not be null or empty");
        try {
            redisTemplate.opsForHash().delete(redisKey, hashKeys);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除指定redis key中的所有mapKey
     *
     * @param redisKey redis key
     */
    public void hdelall(final String redisKey) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        try {
            Set<String> keys = redisTemplate.opsForHash().keys(redisKey);
            for (String value : keys) {
                redisTemplate.opsForHash().delete(redisKey, value);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 指定redisKey插入mapKey，value数据
     *
     * @param redisKey redis key
     * @param hashKey  map key
     */
    public void hset(final String redisKey, final String hashKey, Object value) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Assert.hasText(hashKey, "map key not be null or empty");
        Assert.notNull(value, "map value not be null");
        try {
            redisTemplate.opsForHash().put(redisKey, hashKey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 指定redisKey插入map数据
     *
     * @param redisKey redis key
     * @param map      map
     */
    public void hmset(final String redisKey, final Map<String, Object> map) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Assert.notEmpty(map, "map not be null or empty");
        try {
            redisTemplate.opsForHash().putAll(redisKey, map);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 仅当hashKey不存在时才设置散列hashKey的值
     *
     * @param redisKey
     * @param hashKey
     * @param value
     */
    public void hsetnx(final String redisKey, final String hashKey, Object value) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Assert.hasText(hashKey, "map key not be null or empty");
        Assert.notNull(value, "map value not be null");
        try {
            redisTemplate.opsForHash().putIfAbsent(redisKey, hashKey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取指定redisKey中map对应hashKey的value
     *
     * @param redisKey
     * @param hashKey
     */
    public Object hget(final String redisKey, final String hashKey) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Assert.hasText(hashKey, "map key not be null or empty");
        Object result = null;
        try {
            result = redisTemplate.opsForHash().get(redisKey, hashKey);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取给定hashKeys的值list
     *
     * @param redisKey
     * @param hashKeys
     * @return
     */
    public List<Object> multiget(final String redisKey, Collection hashKeys) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Assert.notEmpty(hashKeys, "hash keys not be null or empty");
        List<Object> result = new ArrayList<>();
        try {
            result = redisTemplate.opsForHash().multiGet(redisKey, hashKeys);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取key所对应的散列表的key
     *
     * @param redisKey
     * @return
     */
    public Set<Object> hashkeys(final String redisKey) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        Set<Object> result = new HashSet<>();
        try {
            result = redisTemplate.opsForHash().keys(redisKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取指定redis key 的 map
     *
     * @param redisKey
     */
    public Map<String, Object> hget(final String redisKey) {
        Assert.hasText(redisKey, "redis key not be null or empty");
        try {
            Set<String> keys = redisTemplate.opsForHash().keys(redisKey);
            Map<String, Object> map = new HashMap<>();
            for (String mapKey : keys) {
                map.put(mapKey, redisTemplate.opsForHash().get(redisKey, mapKey));
            }
            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

//=========================================================== List =====================================================

    /**
     * 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定。
     * <p>
     * 下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。
     * 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     */
    public List<Object> lrange(String redisKey, long start, long end) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(start, "start not be null");
        Assert.notNull(end, "end not be null");
        try {
            return redisTemplate.opsForList().range(redisKey, start, end);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 对一个列表进行修剪
     * 让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除。
     * <p>
     * 举个例子，执行命令 LTRIM list 0 2 ，表示只保留列表 list 的前三个元素，其余元素全部删除。
     * 下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。
     * 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     * 当 key 不是列表类型时，返回一个错误。
     */
    public void ltrim(String redisKey, long start, long end) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(start, "start not be null");
        Assert.notNull(end, "end not be null ");
        try {
            redisTemplate.opsForList().trim(redisKey, start, end);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 返回列表 key 的长度。
     * <p>
     * 如果 key 不存在，则 key 被解释为一个空列表，返回 0 .
     * 如果 key 不是列表类型，返回一个错误。
     */
    public Long llen(String redisKey) {
        Assert.hasText(redisKey, "key not be null or empty");
        try {
            return redisTemplate.opsForList().size(redisKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将一个 value 插入到列表 key 的表头
     * <p>
     * 如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表头：
     * 比如说，对空列表 mylist 执行命令 LPUSH mylist a b c ，列表的值将是 c b a ，这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。
     * 如果 key 不存在，一个空列表会被创建并执行 LPUSH 操作。
     * 当 key 存在但不是列表类型时，返回一个错误。
     */
    public Long lpush(String redisKey, Object value) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(value, "value not be null");
        try {
            return redisTemplate.opsForList().leftPush(redisKey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将 数组 插入到列表 key 的表头
     */
    public Long lpush(String redisKey, Object... values) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.noNullElements(values, "values not be null or empty");
        try {
            return redisTemplate.opsForList().leftPushAll(redisKey, values);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将 集合 插入到列表 key 的表头
     */
    public Long lpush(String redisKey, List<Object> value) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notEmpty(value, "values not be null or empty");
        try {
            return redisTemplate.opsForList().leftPushAll(redisKey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将值 value 插入到列表 key 的表头，当且仅当 key 存在并且是一个列表。
     */
    public Long lpushx(String redisKey, Object value) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(value, "value not be null");
        try {
            return redisTemplate.opsForList().leftPushIfPresent(redisKey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 把value值放到key对应列表中pivot值的左面，如果pivot值存在的话
     */
    public Long linsert(String redisKey, Object pivot, Object value) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(pivot, "pivot not be null");
        Assert.notNull(value, "value not be null");
        try {
            return redisTemplate.opsForList().leftPush(redisKey, pivot, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将所有指定的值插入存储在键的列表的头部。如果键不存在，则在执行推送操作之前将其创建为空列表。（从右边插入）
     */
    public Long rpush(String redisKey, Object value) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(value, "value not be null");
        try {
            return redisTemplate.opsForList().rightPush(redisKey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将 数组 插入存储在键的列表的头部。如果键不存在，则在执行推送操作之前将其创建为空列表。（从右边插入）
     */
    public Long rpush(String redisKey, Object... values) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.noNullElements(values, "values not be null or empty");
        try {
            return redisTemplate.opsForList().rightPushAll(redisKey, values);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将 集合 插入存储在键的列表的头部。如果键不存在，则在执行推送操作之前将其创建为空列表。（从右边插入）
     */
    public Long rpush(String redisKey, List<Object> value) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notEmpty(value, "values not be null or empty");
        try {
            return redisTemplate.opsForList().rightPushAll(redisKey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将 集合 插入存储在键的列表的头部。如果键不存在，则在执行推送操作之前将其创建为空列表。（从右边插入）
     */
    public Long rpushx(String redisKey, Object value) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(value, "value not be null ");
        try {
            return redisTemplate.opsForList().rightPushIfPresent(redisKey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 在列表中index的位置设置value值
     */
    public void lset(String redisKey, Long index, Object value) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(index, "index not be null ");
        Assert.notNull(value, "value not be null ");
        try {
            redisTemplate.opsForList().set(redisKey, index, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 从存储在键中的列表中删除等于值的元素的第一个计数事件。
     * 计数参数以下列方式影响操作：
     * count> 0：删除等于从头到尾移动的值的元素。
     * count <0：删除等于从尾到头移动的值的元素。
     * count = 0：删除等于value的所有元素。
     */
    public Long lrem(String redisKey, Long count, Object value) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(count, "count not be null ");
        Assert.notNull(value, "value not be null ");
        try {
            return redisTemplate.opsForList().remove(redisKey, count, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据下标获取列表中的值，下标是从0开始的
     */
    public Object lindex(String redisKey, Long index) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(index, "index not be null ");
        try {
            return redisTemplate.opsForList().index(redisKey, index);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 弹出最左边的元素，弹出之后该值在列表中将不复存在
     */
    public Object lpop(String redisKey) {
        Assert.hasText(redisKey, "key not be null or empty");
        try {
            return redisTemplate.opsForList().leftPop(redisKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 弹出最左边的元素，弹出之后该值在列表中将不复存在
     */
    public Object lpop(String redisKey, Long timeout, TimeUnit unit) {
        Assert.hasText(redisKey, "key not be null or empty");
        Assert.notNull(timeout, "timeout not be null ");
        Assert.notNull(unit, "unit not be null ");
        try {
            return redisTemplate.opsForList().leftPop(redisKey, timeout, unit);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
